JS传值与传引用 深拷贝浅拷贝

1.js基本类型的赋值关系

1
2
3
4
5
var a = 5;
var b = a;
b = b+3;
alert(b);//8 b的改变不会影响a的值
alert(a);//5

2.数组赋值关系

1
2
3
4
5
var a = [1,2,3];
var b = a;
b.push(4);
alert(b); //[1,2,3,4]
alert(a); //[1,2,3,4]

  在上面的例子中,b的值发生了改变影响到了a的值。这就构成了一种对象(函数)间的引用关系。

1
2
3
4
5
var a = [1,2,3];
var b = a;
b = [1,2,3,4];
alert(b); //[1,2,3,4]
alert(a); //[1,2,3]

  在两个例子中,a和b都是引用关系,共用一块内存地址。第一个例子中,b的值发生了改变,a的值也跟着变化。
而第二个例子中,将一个新的数组分配给b则相当于给b开辟了新的内存空间,所以b的值不会改变a的值。

3.对象赋值与引用

  下面再试一下对象的引用关系。

1
2
3
4
5
6
var obj = {
a:10
}
var obj2 = obj;
obj2.a = 20;
alert(obj.a);//20

  如果对象直接用等于号赋值,改变obj2的值会使obj的值发生改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
var obj = {
a:10
}
function copy(obj){
var newObj = {};
for(var attr in obj){
newObj[attr] = obj[attr];
}
return newObj;
}
var obj2 = copy(obj);
obj2.a = 20;
alert(obj.a);//10

  在上面的例子中,我们需要赋值对象而不是引用对象的话,需要一个copy函数,将对象里面的值进行赋值操作。这种形式在JS中被称为浅拷贝。相对应的是深拷贝的模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj = {
a:{
b:10
}
}
function copy(obj){
var newObj = {};
for(var attr in obj){
newObj[attr] = obj[attr];
}
return newObj;
}
var obj2 = copy(obj);
obj2.a.b = 20;
alert(obj.a.b);//20

  我们可以发现如果a里面的值是一个json的话,其实本质上还是一种引用关系。更改obj2,obj的值依然会受到影响。因为浅拷贝只是拷贝了一层,当我们用copy函数时还是把整体的对象赋值,所以还是对象的引用关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var obj = {
a:{
b:10
}
}
function deepCopy(obj){
if(typeof obj != 'object'){ //终止条件:obj不是对象作为递归的出口。
return obj;
}
var newObj = {};
for(var attr in obj){
newObj[attr] = deepCopy(obj[attr]);
}
return newObj;
}
var obj2 = deepCopy(obj);
obj2.a.b = 20;
alert(obj.a.b);//10

以上为深拷贝的例子。采用的是递归的方式,深拷贝可以复制多次直至结束。